package com.zhdl.modules.process.service;

import cn.hutool.core.util.HexUtil;
import com.github.xingshuangs.iot.protocol.s7.service.S7PLC;
import com.project.common.util.DelayUtil;
import com.zhdl.common.ytools.BaseConversionTools;
import com.zhdl.common.ytools.BitConversionTools;
import com.zhdl.common.ytools.callback.CommonCallback;
import com.zhdl.hardware_contact.hardware_config.entity.ProjectConfiguration;
import com.zhdl.hardware_contact.hardware_web.service.HardwareContactService;
import com.zhdl.modules.common.warn.service.RunWarnService;
import com.zhdl.modules.demo.DCHTProcess.MotorInterface;
import com.zhdl.modules.process.ProcessStatusExchangeHolder;
import com.zhdl.modules.process.common.GetPLCValue;
import com.zhdl.modules.process.dto.MyEx;
import com.zhdl.network.strategy.common_server.impl.CommonServerSendServiceImpl;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

@Slf4j
@Service

@Data

public class ProjectConfigProcessService implements GetPLCValue {

    @Resource
    private HardwareContactService hardwareContactService;

    //RAM中的参数列表
    public static List<ProjectConfiguration> projectConfigurations;

    @Resource
    CommonServerSendServiceImpl commonServerSendService;

    @Resource
    S7PLC s7PLC;

    @Resource
    MotorInterface motorInterface;
    @Resource
    RunWarnService runWarnService;
    private CommonCallback<ProjectConfiguration> exchangeBitConfigChange;
    public static final String COMMON_TEST_BIT = "common_test_bit";
    @Resource
    ThreadPoolTaskScheduler threadPoolTaskScheduler;
    /**
     * 初始化项目的配置信息
     */
    public void initProjectConfiguration(String projectName) {
        projectConfigurations = hardwareContactService.initProjectConfiguration(projectName);
        projectConfigurations.add(new ProjectConfiguration(COMMON_TEST_BIT,"0",1));
        threadPoolTaskScheduler.scheduleWithFixedDelay(() -> {
            int i = new Random().nextInt(10);
            if (i>=3){
                getValue(COMMON_TEST_BIT).setValue("1");
            }else{
                getValue(COMMON_TEST_BIT).setValue("0");
            }
        },1000);
        if (!commonServerSendService.serverClientList.keySet().isEmpty()) {
            for (String s : commonServerSendService.serverClientList.keySet()) {
                if (s.split(":")[1].equals("2000")) {
                    commonServerSendService.setDataCallBack(s, new CommonCallback<String>() {
                        @Override
                        public void statusCallback(String s) {
                            //log.info(s);
                            readProjectConfigToRAM(s);
                        }
                    });
                }
            }

        }
        //readProjectConfigByAddress("DB3.0", 542, 0);
      //  readProjectConfigByAddress("DB3.0", 156, 0);
    }

    private String plcValue = "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000" + "000000000000000000";


    private List<CommonCallback<List<ProjectConfiguration>>> changeCallBacks = new ArrayList<>();
    //历史配置信息 Map
    Map<String, String> lastValue = new HashMap<>();
    private List<CommonCallback<List<MyEx>>> errCallBacks = new ArrayList<>();
    private boolean plcReadComplete = false;

    private void notifyCallbacks(List<ProjectConfiguration> projectParmaList) {
        if (!changeCallBacks.isEmpty()) {
            for (CommonCallback<List<ProjectConfiguration>> changeCallBack : changeCallBacks) {
                changeCallBack.statusCallback(projectParmaList);
            }
        }
    }
    private String DB3PLCValue;
    public void readProjectConfigByAddress(String Address, Integer length, int count) {
        if (count ==0) {
            DB3PLCValue = "";
        }
        log.info("readProjectConfigByAddress Address = "+Address +"---length="+length+"---count"+count);
        count++;
        try {
            byte[] bytes = s7PLC.readByte(Address, length>200?200:length);
             DB3PLCValue += HexUtil.encodeHexStr(bytes);
            log.info(HexUtil.encodeHexStr(bytes));
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (length > 200) {
            String address = "DB3."+count*200;
            readProjectConfigByAddress(address,length-200,count);
        }else {
            log.info("DB3完整数据"+DB3PLCValue);
            for (ProjectConfiguration projectConfiguration : projectConfigurations) {
                if (projectConfiguration.getDbAddress().equals("DB3")) {
                    lastValue.put(projectConfiguration.getField(), projectConfiguration.getValue());
                    processProjectConfiguration(DB3PLCValue, projectConfiguration);
                }
            }
        }

    }


    /**
     * 解析PLC值 TO RAM
     *
     * @param readValue plc的值
     */
    public void readProjectConfigToRAM(String readValue) {
        //获取PLCValue
        plcValue = readValue;

        //初始化一个异常列表
        List<MyEx> exList = new ArrayList<>();
        if (projectConfigurations == null || projectConfigurations.isEmpty()) {
            return;
        }
        //配置列表 Key为filed value为value
        for (ProjectConfiguration projectConfiguration : projectConfigurations) {
            if (projectConfiguration.getDbAddress().equals("DB1")) {
                lastValue.put(projectConfiguration.getField(), projectConfiguration.getValue());
                processProjectConfiguration(plcValue, projectConfiguration);
            }
        }
        notifyCallbacks(projectConfigurations);
        /*
            第一次读取保存到数据库信息
         */
        if (!plcReadComplete) {
            plcReadComplete = true;
            projectConfigurations.forEach(projectConfiguration -> {
                hardwareContactService.saveProjectConfig(projectConfiguration);
            });
        }
    }


    /**
     * 根据值类型进行转换
     *
     * @param readValue            PLC的值
     * @param projectConfiguration PLC的配置信息
     */
    private void processProjectConfiguration(String readValue, ProjectConfiguration projectConfiguration) {
        String address = projectConfiguration.getAddress();
        switch (projectConfiguration.getValueType()) {
            case 1 -> {
                projectConfiguration.setValue(processBitValue(readValue, address));
                checkAlarm(projectConfiguration);
            }
            case 2 -> projectConfiguration.setValue(processIntValue(readValue, address));
            case 3 -> projectConfiguration.setValue(processFloatValue(readValue, address));
            default ->
                // 如果在类型之外，则抛出异常
                    throw new IllegalArgumentException("Unsupported value type: " + projectConfiguration.getValueType());
        }
    }

    /* 转bit */
    public String processBitValue(String plcValue, String address) {
        String[] split = address.split("\\.");
        int wordAddress = Integer.parseInt(split[0]);
        int bit = split.length == 1 ? (wordAddress % 2 == 0 ? 0 : 8) : (wordAddress % 2 == 0 ? Integer.parseInt(split[1]) : Integer.parseInt(split[1]) + 8);
        String hexValueByDecAddress = BitConversionTools.readHexByDecAddress(plcValue, wordAddress / 2);
        String bitValueByHex = BitConversionTools.HexStrToReversalBit(hexValueByDecAddress);

        StringBuilder stringAfter = new StringBuilder(bitValueByHex.substring(0, 8)).reverse();

        StringBuilder stringBefore = new StringBuilder(bitValueByHex.substring(8, 16)).reverse();

        bitValueByHex = stringAfter + stringBefore.toString();

//        if (split[0].equals("63")) {
//            log.info("地址查看--->{},---->{}---->bit{}--->{}", hexValueByDecAddress, bitValueByHex, bit, bitValueByHex.charAt(bit));
//        }
//        if (address.equals("60")){
//            machineConf.getManualModel().setValue(String.valueOf(bitValueByHex.charAt(bit)));
//        }else if (address.equals("60.1")){
//            machineConf.getAutoModel().setValue(String.valueOf(bitValueByHex.charAt(bit)));
//        }
        // PropertyDescriptor[] propertyDescriptors = BeanUtil.getPropertyDescriptors(MachineConf.class);
       if (address.equals("60")||address.equals("60.1")||address.equals("60.2")||address.equals("60.3")||address.equals("60.4")||address.equals("60.5")||address.equals("60.6")){
           ProcessStatusExchangeHolder.machineConf.checkValue(address,String.valueOf(bitValueByHex.charAt(bit)));
       }
        return String.valueOf(bitValueByHex.charAt(bit));
    }

    /* 转int */
    private String processIntValue(String plcValue, String address) {
        int wordAddress = Integer.parseInt(address);
        String hexValueByDecAddress = BitConversionTools.readHexByDecAddress(plcValue, wordAddress / 2);
        int hexInt = BaseConversionTools.hexToInt(hexValueByDecAddress);
        return hexInt + "";
    }

    /* 转float */
    private String processFloatValue(String plcValue, String address) {
        int wordAddress = Integer.parseInt(address);
        try {
            String hexValueByDecAddress = BitConversionTools.readHexByDecAddress(plcValue, wordAddress / 2, wordAddress / 2 + 1);
            return "" + BaseConversionTools.hexToFloat(hexValueByDecAddress);
        }catch (Exception e){
            return "0.0";
        }
//        log.error(address);

    }

    /**
     * 设置PLC配置信息
     *
     * @param filed 字段名儿
     * @param value 十六进制 Value
     * @return /
     */
    private String setPlcProjectConfig(String filed, String value) {
        ProjectConfiguration config = getProjectConfiguration(projectConfigurations, filed);
        config.setValue(value);
        return setPlcProjectConfig(config);
    }

    public String setPlcProjectConfig(ProjectConfiguration projectConfiguration) {
        //获取要查询的字段
        String field = projectConfiguration.getField();
        ProjectConfiguration config = getProjectConfiguration(projectConfigurations, field);
        String validateResult = validateConfiguration(config);

        // 验证当前字段查询的结果
        if (!"success".equals(validateResult)) {
            return validateResult;
        }

        String address = projectConfiguration.getAddress();
        String value = projectConfiguration.getValue();
        int valueType = projectConfiguration.getValueType();

        if (address.contains(".")) {
            String[] parts = address.split("\\.", 2);
            address = parts[0];

            int byteIndex = Integer.parseInt(parts[0]);
            int bitIndex = Integer.parseInt(parts[1]);

            // 调整bitIndex（如果字节索引为奇数，则bitIndex+8）
            if (byteIndex % 2 != 0) {
                bitIndex += 8;
            }
            String hexByte = BitConversionTools.readHexByDecAddress(plcValue, byteIndex / 2);
            char newValueChar = value.charAt(0); // 假设只处理单个字符的值
            value = BitConversionTools.yWriteValueByDecIndex(hexByte, bitIndex, newValueChar);
        } else {
            if (valueType == 2) {
                value = BaseConversionTools.intToShortHex(Integer.parseInt(value));
            } else if (valueType == 3) {
                value = BaseConversionTools.intToIntHex(Integer.parseInt(value));
            } else {
                log.info("类型未知");
            }
        }
        address = BaseConversionTools.intToShortHex(Integer.parseInt(address) / 2);
        // 发送十六进制 代码
        return "success";
    }

    /**
     * 通过字段，寻找内存中的PLC配置信息
     *
     * @param projectConfigurations 内存中的参数信息s
     * @param filed                 字段
     * @return /
     */
    private ProjectConfiguration getProjectConfiguration(List<ProjectConfiguration> projectConfigurations, String filed) {
        //判断是否条件为非空
        if (projectConfigurations == null) {
            return null;
        }
        Optional<ProjectConfiguration> matchingConfiguration = projectConfigurations.stream().filter(projectConfiguration -> projectConfiguration.getField().equals(filed)) // 注意：这里应该是"field"，可能是个拼写错误
                .findFirst();
        return matchingConfiguration.orElse(null);
    }

    /**
     * 验证是否有权限编写
     *
     * @param configuration PLC配置信息
     * @return /
     */
    private String validateConfiguration(ProjectConfiguration configuration) {
        if (configuration == null) {
            log.info("ConfigurationPLc字段无法匹配!");
//            throw new IllegalArgumentException("ConfigurationPLc not found for the given field");
            return "error_filed";
        }
        if (configuration.getPermissions() == 1) {
            log.info("ConfigurationPLc无权限!");
//            throw new IllegalStateException("No permissions for this ConfigurationPLc");
            return "error_permissions";
        }
        return "success";
    }

    private void checkAlarm(ProjectConfiguration projectConfiguration){
        if (("alarm").equals(projectConfiguration.getGroupType())){
            if (projectConfiguration.getValue().equals("1") && "0".equals(lastValue.get(projectConfiguration.getField()))) {
                String address = projectConfiguration.getAddress();
                String[] split = address.split("\\.");
                int code;
                if (split.length == 1) {
                    code = Integer.parseInt(address);
                }else {
                    code = Integer.parseInt(split[0]+split[1]);
                }
                runWarnService.addNewWarnService(projectConfiguration.getRemarks(),code);
            }
        }
    }
    /**
     * 手动更新内存值
     *
     * @param id
     * @param Value
     */
    public void updateRamConfigurationValue(Integer id, String Value) {
        for (ProjectConfiguration projectConfiguration : projectConfigurations) {
            Integer tid = projectConfiguration.getId();
            if (id.equals(tid)) {
                projectConfiguration.setValue(Value);
                break;
            }
        }
    }


    @Override
    public ProjectConfiguration getValue(String field) {
        for (ProjectConfiguration configurationPLc : projectConfigurations) {
            if (configurationPLc.getField().equals(field)) {
                return configurationPLc;
            }
        }
        return null;
    }
}
